<?php
/**
 * Socket Verbindung erstellen
 *
 * @author		Joachim Ruf
 * @copyright	Copyright (c) 2003-2013 Loresoft Software (http://www.loresoft.de)
 * @license		http://yapary.loresoft.de/lizenzbedingungen     New BSD License
 * @TODO
 * */


Class Yapary_WWW_Socket
{
    private $oException    = NULL;
    private $proxy         = NULL;
    private $proxyPort     = NULL;

    private $http          = NULL;

    private $host          = NULL;
    private $hostPath      = NULL;
    private $hostPort      = NULL;

    private $timeout       = NULL;
    private $streamTimeout = NULL;
    private $oTiming       = NULL;

    private $arrPostData   = array();
    private $arrCookieData = array();
    private $arrHeaderData = array();
    private $arrFputs      = array();


    function __construct ($_http = "HTTP/1.0") {
        $this->http       = $_http;
        $this->oException = new Yapary_Exception_Exception();
        $this->oTiming    = new Yapary_Time_Timing();
    }

    /**
     * Definiert den Proxy oder Host
     * @param string $host		: Host {www.website.de}
     * @param string $hostPath	: Host-Pfad {/index.html}
     * @param string $hostPort	: Port, ueber welchen die Verbindung erfolgen soll {80}
     * @return void
     * */
    public function setHost ($_host, $_hostPath, $_hostPort, $_timeout = 10, $_streamTimeout = 10) {
        $this->host          = $_host;
        $this->hostPath      = $_hostPath;
        $this->hostPort      = $_hostPort;
        $this->timeout       = $_timeout;
        $this->streamTimeout = $_streamTimeout;
    }

    /**
     * Definiert einen Proxy, ueber welchen die Daten geleitet werden sollen.
     * Hierbei wird der Port von $HostPort mit proxyPort ueberschrieben
     * @param string $proxy		: Proxy {141.142.143.1} oder Host {www.website.de}
     * @param int    $proxyPort	: Port, ueber welchen die Verbindung erfolgen soll {3128}
     * @return void
     * */
    public function setProxy ($proxy, $proxyPort) {
        $this->proxy     = $proxy;
        $this->proxyPort = $proxyPort;
    }


    /**
     * Fuegt einen neuen Post-Datensatz im Format {&$name=$value} hinzu
     * @param string $name		: Variablenname {username}
     * @param string $value		: Variablenwert {myName}
     * @return void
     * */
    public function addPostData ($name, $value) {
        $this->arrPostData[] = "$name=$value";
    }

    private function getPostData () {
        $result = '';

        if ($this->arrPostData) {
            $result = implode('&', $this->arrPostData);
        }

        return $result;
    }

    /**
     * Fuegt neue Cookie-Informationen im Format {$name=$value} hinzu
     * @param string $option	: Optionsname {User-Agent}
     * @param string $value		: Variablenwert {Mozilla 5.0...}
     * @return void
     * */
    public function addCookieData ($name, $value) {
        $this->arrCookieData[$name] = $value;
    }

    private function getCookieData () {
        $result = '';

        if ($this->arrCookieData) {
            try {
                while (list($key, $val) = each($this->arrCookieData)) {
                    $result .= "Cookie: $key=$val\r\n";
                }
            } catch (Exception $e) {
                $this->oException->add('Error while inserting cookie data');
            }
        }

        return $result;
    }

    /**
     * Fuegt neue Header-Informationen im Format {$option: $value} hinzu
     * @param string $option	: Optionsname {User-Agent}
     * @param string $value		: Variablenwert {Mozilla 5.0...}
     * @return void
     * */
    public function addHeaderData ($option, $value) {
        $this->arrHeaderData[$option] = $value;
    }

    private function getHeaderData () {
        $result = '';

        if ($this->arrHeaderData) {
            try {
                while (list($key, $val) = each($this->arrHeaderData)) {
                    $result .= "$key: $val\r\n";
                }
            } catch (Exception $e) {
                $this->oException->add('Error while inserting header data');
            }
        }

        return $result;
    }

    /**
     * Testet, ob der definierte Proxy verfuegbar ist
     * @return $fp
     * */
    private function getProxy () {
        try {
        	$fp = @fsockopen($this->proxy, $this->proxyPort, $errno, $errstr, $this->timeout);
        	if ($fp) {
                stream_set_blocking($fp, 0); // non blocking
                stream_set_timeout($fp, $this->streamTimeout);
        	} else {
        	    $this->oException->add('Error while opening socket proxy connection errno['.$errno.'] errstr['.$errstr.']');
        	}
        } catch (Exception $e) {
            $fp = NULL;
            $this->oException->add('Error while opening socket proxy connection errno['.$errno.'] errstr['.$errstr.']');
        }

        return $fp;
    }

    /**
     * Testet, ob der definierte Proxy verfuegbar ist
     * @return $fp
     * */
    private function getHost () {
        try {
        	$fp = @fsockopen($this->host, $this->hostPort, $errno, $errstr, $this->timeout);
        	if ($fp) {
            	stream_set_blocking($fp, 0); // non blocking
                stream_set_timeout($fp, $this->streamTimeout);
        	} else {
                $this->oException->add('Error while opening socket host connection errno['.$errno.'] errstr['.$errstr.']');
        	}
        } catch (Exception $e) {
            $fp = NULL;
            $this->oException->add('Error while opening socket host connection errno['.$errno.'] errstr['.$errstr.']');
        }

        return $fp;

    }

    /**
     * Sendet den definierten Request
     * @return array|NULL
     * */
    public function sendPostRequest () {
        $fp       = NULL;
        $header   = '';
        $arrRes   = array();
        $postData = $this->getPostData();

        $this->oTiming->start();
        if ($this->proxy != NULL && $this->proxyPort != NULL) { // per Proxy verbinden
            if (!($fp = $this->getProxy())) {
                return NULL;
            }

            $header .= "POST http://$this->host$this->hostPath ".$this->http."r\n";
            $header .= "Host: $this->host\r\n";
        } else { // direkt zum Host
            if (!($fp = $this->getHost())) {
                return NULL;
            }

            $header .= "POST $this->hostPath ".$this->http."\r\n";
            $header .= "Host: $this->host\r\n";
        }
        $this->oTiming->stop();
        $arrRes[] = 'Access-Time: '.$this->oTiming->get(Yapary_Time_Timing::msec)."\r\n";

        $header .= $this->getHeaderData();
        $header .= "Content-Length: ". strlen($postData) ."\r\n";
        $header .= $this->getCookieData();
        $header .= "Connection: close\r\n\r\n";
        $header .= $postData;

        fwrite($fp, $header);

        ini_set('auto_detect_line_endings', 1);
        try {
            while(!feof($fp)) {
                $tmp = fgets($fp, 4*1024);
                if (strlen($tmp) != 0) {
                    //echo $tmp.'; ';
                    $arrRes[] = $tmp;
                }
            }
        } catch (Exception $e) {
            $this->oException->add('Error while getting response data');
        }
        $this->oTiming->stop();
        $arrRes = array_merge(array('Load-Time: '.$this->oTiming->get(Yapary_Time_Timing::msec)."\r\n"), $arrRes);

        fclose($fp);
        return $arrRes;
    }

    /**
     * Liefert die Exception-Klasse
     * @return Yapary_Exception_Exception
     * */
    public function Exception () {
        return $this->oException;
    }
}

?>